package com.shanzmoo.job.manager;

import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.shanzmoo.db.job.entity.ScheduleJobEntity;
import com.shanzmoo.db.job.entity.vo.ScheduleJobVo;
import com.shanzmoo.db.job.service.IScheduleJobService;
import com.shanzmoo.job.util.ScheduleUtil;
import lombok.extern.slf4j.Slf4j;
import org.quartz.CronTrigger;
import org.quartz.Scheduler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 调度任务管理器
 *
 * @author： Gzhao 2021/1/31
 */
@Slf4j
@Component
public class ScheduleJobManager {

    @Resource
    private Scheduler scheduler;

    @Autowired
    private IScheduleJobService scheduleJobService;

    /**
     * 定时器初始化
     */
    @PostConstruct
    public void init() {
        List<ScheduleJobEntity> scheduleJobList = scheduleJobService.list(
                new QueryWrapper<ScheduleJobEntity>()
                        .eq("deleted", false)
        );
        for (ScheduleJobEntity scheduleJob : scheduleJobList) {
            try {
                CronTrigger cronTrigger = ScheduleUtil.getCronTrigger(scheduler, scheduleJob.getJobId());

                if (cronTrigger == null) {
                    ScheduleUtil.createJob(scheduler, scheduleJob);
                } else {
                    ScheduleUtil.updateJob(scheduler, scheduleJob);
                }
            } catch (Exception e) {
                log.error("定时任务：{} 初始化失败！！！", scheduleJob.getRemark(), e);
            }
        }
    }

    public List<ScheduleJobVo> allList() {
        List<ScheduleJobEntity> list = scheduleJobService.list(
                new QueryWrapper<ScheduleJobEntity>()
                        .eq("deleted", false)
        );

        return list.stream().map(e -> {
            return ScheduleJobVo.create(e);
        }).collect(Collectors.toList());
    }

    @Transactional(rollbackFor = Exception.class)
    public void updateJob(ScheduleJobEntity jobEntity) {
        scheduleJobService.updateById(jobEntity);

        ScheduleJobEntity newScheduleJob = scheduleJobService.getById(jobEntity.getJobId());

        ScheduleUtil.updateJob(scheduler, newScheduleJob);
    }

    @Transactional(rollbackFor = Exception.class)
    public void saveJob(ScheduleJobEntity jobEntity) {
        scheduleJobService.save(jobEntity);

        ScheduleUtil.createJob(scheduler, jobEntity);
    }

    public void deleteJob(Long jobId) {
        ScheduleJobEntity scheduleJob = scheduleJobService.getById(jobId);

        Assert.isTrue(scheduleJob == null || scheduleJob.getStatus(), "job不存在或者正在启动中,删除失败");

        scheduleJobService.update(
                new ScheduleJobEntity().setDeleted(true),
                new UpdateWrapper<ScheduleJobEntity>().eq("job_id", jobId)
        );
    }

    public void run(Long jobId) {
        ScheduleJobEntity scheduleJob = scheduleJobService.getById(jobId);
        ScheduleUtil.run(scheduler, scheduleJob);
    }

    @Transactional(rollbackFor = Exception.class)
    public void pause(Long jobId) {
        ScheduleJobEntity scheduleJob = scheduleJobService.getById(jobId);

        Assert.isTrue(scheduleJob == null || scheduleJob.getStatus(), "job不存在或者已暂停中,暂停失败");

        scheduleJobService.update(
                new ScheduleJobEntity().setStatus(false),
                new UpdateWrapper<ScheduleJobEntity>().eq("job_id", jobId)
        );
        ScheduleUtil.pauseJob(scheduler, jobId);
    }

    @Transactional(rollbackFor = Exception.class)
    public void start(Long jobId) {
        ScheduleJobEntity scheduleJob = scheduleJobService.getById(jobId);

        Assert.isTrue(scheduleJob == null || !scheduleJob.getStatus(), "job不存在或者已正在运行中, 启动失败");

        scheduleJobService.update(
                new ScheduleJobEntity().setStatus(true),
                new UpdateWrapper<ScheduleJobEntity>().eq("job_id", jobId)
        );
        ScheduleUtil.resumeJob(scheduler, jobId);
    }
}
